using System;
using System.IO;
using System.Net;
using System.Text;
using System.Globalization; //for cultural settings (user on different locale than us)
using System.Xml;
using System.Collections.Specialized;
using System.Management;    //for WMI to calculate IP metrics for multiple adapators
using System.Net.NetworkInformation;
using System.Data;
using System.Configuration;

namespace CopyTimer
{
    class Program
    {
        #region define vars
        public enum ActionType { Copy, Delete, MD, RD };

        static TextWriter Output = Console.Out;
        static TextWriter Error = Console.Error;
        
        static StringCollection strarrActivityLog = new StringCollection();
        static string strXMLResults = ""; 
        
        static Utility TestUtility = new Utility();

        //TODO: make a class for some file transactions
        static double dTotalTransferTime = 0;
        static double iTotalTransferSize = 0;
        static double dFileDLTime1 = 0;
        static double dFileULTime1 = 0;
        static double iFileSize1 = 0;
        static double dFileDLTime2 = 0;
        static double dFileULTime2 = 0;
        static double iFileSize2 = 0;
        static double dFileDLTime3 = 0;
        static double dFileULTime3 = 0;
        static double iFileSize3 = 0;
        static string FileDL1Msg = "";
        static string FileUL1Msg = "";
        static string FileDL2Msg = "";
        static string FileUL2Msg = "";
        static string FileDL3Msg = "";
        static string FileUL3Msg = "";
        static bool FileDL1Success = true;
        static bool FileUL1Success = true;
        static bool FileDL2Success = true;
        static bool FileUL2Success = true;
        static bool FileDL3Success = true;
        static bool FileUL3Success = true;

        static double warmupTime = 0;
        static bool warmupSuccess = true;
        static string warmupMsg = "";

        static string MachineName = Environment.MachineName;

        static string ping_time = "";
        static Uri server_name;

        static string currentIP;   //the current IP with the lowest metric (cost) is the one that will be used for transfers
        static string currentEthernetDescription;
        static UInt32 currentLowestMetric = UInt32.MaxValue;

        static string CopytimerVersion = "1.3";
        static string ResultsListName;
        static string TestDocumentsUrl;
        static string File1;
        static string File2;
        static string File3;

        #endregion

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {

            try
            {
                //name of list to upload results
                ResultsListName = CopyTimer.Properties.Settings.Default.ResultListName;

                //pick one for location of 3 files to test
                TestDocumentsUrl = CopyTimer.Properties.Settings.Default.DocLibUrl; //location of the following 3 files
                File1 = CopyTimer.Properties.Settings.Default.File1;    //file names
                File2 = CopyTimer.Properties.Settings.Default.File2;
                File3 = CopyTimer.Properties.Settings.Default.File3;
                
            }
            catch (Exception e)
            {
                Console.WriteLine("Error reading from config file. Ensure that your copytimer.config exists in the same directory as your exe");
                Console.WriteLine("Exception: " + e.Message);
                return;
            }
            try
            {
                bool doesListExist = false;
                ResultsList.Lists listService = new ResultsList.Lists();
                listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                XmlNode node = listService.GetListCollection();
                XmlNodeList nodelist = node.ChildNodes;

                foreach(XmlNode child in nodelist)
                {
                    //check if list with this name already exists
                    if (child.Attributes["Title"].Value == ResultsListName)
                    {
                        doesListExist = true;
                        
                        //it's not a custom list, so its some other list not for copytimer
                        if (child.Attributes["ServerTemplate"].Value != "100")
                        {
                            Console.WriteLine("List with that name exists and list type is not custom. Change the list name.");
                            return;
                        }
                    }
                }

                //if the list doesn't already exist, create it
                if (!doesListExist)
                {
                    Console.WriteLine("Creating list to hold results.");
                    bool CreateListSuccess = CreateCustomResultsList(ResultsListName, "List for holding Copytimer test results.", Console.Out, Console.Error);

                    if (!CreateListSuccess)
                    {
                        Console.WriteLine("Error creating the list to post results to.");
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            ConductTest(TestDocumentsUrl, ResultsListName, Console.Out, Console.Error); 

            Console.WriteLine(Environment.NewLine + "Test now complete. You may close this window.");
        }

		static void ConductTest(string SiteURL, string ResultsListName, TextWriter Output, TextWriter Error)
        {
            #region setupvars
            //reset test variables
			strarrActivityLog = new StringCollection();
			strXMLResults = ""; 

			string UniqueTestID = Guid.NewGuid().ToString();
            IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());

			//start the xml log (this is saved locally on client machine and attached to the list item)
			strXMLResults = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";
            strXMLResults += "<Results><TestRun><Machine MachineName='" + MachineName + "' HostName='" + ipEntry.HostName + "'>";

            //get ping time / IP address
            server_name = new Uri(SiteURL);
            ping_time = ping_test(server_name.Host);
            IFormatProvider USCulture = new CultureInfo("en-US", false);    //convert the datetimes to US for printout

            bool ip_ret = determine_ip_used();

            if (!ip_ret)  //error with IP / WMI
            {
                Console.WriteLine("Error obtaining IP information: {0}", ip_ret);
                currentEthernetDescription = "Error";
                currentIP = "Error";
            }

            //display some console output
            Console.WriteLine("Copytimer Version: {0}", CopytimerVersion);
            Console.WriteLine("{0}", ResultsListName);  //this is the name of the list where results will be posted.. relates to web reference
            Console.WriteLine("Web Server Name: {0}", server_name.Host);
            Console.WriteLine("Ping Time: {0}", ping_time);
            Console.WriteLine("IP Address: {0}", currentIP);
            Console.WriteLine("Description: {0}", currentEthernetDescription);
            Console.WriteLine("{0}Test now running. Do not close this window.{0}", Environment.NewLine);

            //setup the xml output
            strXMLResults += "<IPAddress IP='" + currentIP.ToString() + "'/>";
            strXMLResults += "<Server HOST='" + server_name.Host.ToString() + "'/>";
            strXMLResults += "<PingTime Ping='" + ping_time + "'/>";
            strXMLResults += "<Ethernet Card='" + currentEthernetDescription.ToString() + "'/>";
            strXMLResults += "<Copytimer Version='" + CopytimerVersion + "'/>";
            strXMLResults += "<ResultsList Name='" + ResultsListName + "'/>";
			strXMLResults += "</Machine>";
           
            #endregion

            UtilityOperationResults Results;
            
            //do file download tests
            //this first one is a warm up to intiate the session with the server
            //it is duplicated in the next step but should be much quicker the 2nd time

            Console.WriteLine("Warm up test running...{0}", Environment.NewLine);
            Results = DoOperation(ActionType.Copy, SiteURL + "File1.doc", UniqueTestID + "_File1.doc");
            warmupTime = Results.OperationTime.TotalSeconds;
            iFileSize1 = Results.TransferSize;
            warmupMsg = Results.Message;
            warmupSuccess = Results.Success;
            Console.WriteLine("Warm up test finished..{0}", Environment.NewLine);

            strXMLResults += "<WarmUp Time='" + warmupTime.ToString(USCulture) + "' Status='" + warmupSuccess.ToString() + "' Message='" + warmupMsg.ToString() + "'/>";

            //start download tests
            Console.WriteLine("Tests now running..{0}", Environment.NewLine);
            Results = DoOperation(ActionType.Copy, SiteURL + "File1.doc", UniqueTestID + "_File1.doc");
            dFileDLTime1 = Results.OperationTime.TotalSeconds;
            iFileSize1 = Results.TransferSize;
            FileDL1Msg = Results.Message;
            FileDL1Success = Results.Success;

            Results = DoOperation(ActionType.Copy, SiteURL + "File2.doc", UniqueTestID + "_File2.doc");
            dFileDLTime2 = Results.OperationTime.TotalSeconds;
            iFileSize2 = Results.TransferSize;
            FileDL2Msg = Results.Message;
            FileDL2Success = Results.Success;

            Results = DoOperation(ActionType.Copy, SiteURL + "File3.doc", UniqueTestID + "_File3.doc");
            dFileDLTime3 = Results.OperationTime.TotalSeconds;
            iFileSize3 = Results.TransferSize;
            FileDL3Msg = Results.Message;
            FileDL3Success = Results.Success;
           
            //create temporary server location
            Results = DoOperation(ActionType.MD, "", SiteURL + MachineName);

            //do file upload tests
            Results = DoOperation(ActionType.Copy, UniqueTestID + "_File1.doc", SiteURL + MachineName + "/" + UniqueTestID + "_File1.doc");
            dFileULTime1 = Results.OperationTime.TotalSeconds;
            FileUL1Msg = Results.Message;
            FileUL1Success = Results.Success;
            
            Results = DoOperation(ActionType.Copy, UniqueTestID + "_File2.doc", SiteURL + MachineName + "/" + UniqueTestID + "_File2.doc");
            dFileULTime2 = Results.OperationTime.TotalSeconds;
            FileUL2Msg = Results.Message;
            FileUL2Success = Results.Success;

            Results = DoOperation(ActionType.Copy, UniqueTestID + "_File3.doc", SiteURL + MachineName + "/" + UniqueTestID + "_File3.doc");
            dFileULTime3 = Results.OperationTime.TotalSeconds;
            FileUL3Msg = Results.Message;
            FileUL3Success = Results.Success;

            dTotalTransferTime = dFileDLTime1 + dFileULTime1 + dFileDLTime2 + dFileULTime2 + dFileDLTime3 + dFileULTime3;
            iTotalTransferSize = (iFileSize1 + iFileSize2 + iFileSize3)/2;

            //clean up temporary local files
            Results = DoOperation(ActionType.Delete, "", UniqueTestID + "_File1.doc");
            Results = DoOperation(ActionType.Delete, "", UniqueTestID + "_File2.doc");
            Results = DoOperation(ActionType.Delete, "", UniqueTestID + "_File3.doc");

            //clean up temporary server files
            Results = DoOperation(ActionType.Delete, "", SiteURL + MachineName + "/" + UniqueTestID + "_File1.doc");
            Results = DoOperation(ActionType.Delete, "", SiteURL + MachineName + "/" + UniqueTestID + "_File2.doc");
            Results = DoOperation(ActionType.Delete, "", SiteURL + MachineName + "/" + UniqueTestID + "_File3.doc");
            Results = DoOperation(ActionType.RD, "", SiteURL + MachineName);
            
            //close out xml log
            strXMLResults += "</TestRun>";
            
            //save the results to file and list
            SaveResults(ResultsListName);
        }

        static UtilityOperationResults DoOperation(ActionType Action, string Source, string Target)
        {
            LogTest(Action, Source, Target);

            UtilityOperationResults Results;
            switch (Action)
            {
                case ActionType.Copy:
                    Results = TestUtility.CopyFile(Source, Target, true);
                    break;
                case ActionType.Delete:
                    Results = TestUtility.DeleteFile(Target);
                    break;
                case ActionType.MD:
                    Results = TestUtility.CreateFolder(Target);
                    break;
                case ActionType.RD:
                    Results = TestUtility.DeleteFolder(Target);
                    break;
                default:
                    Results = new UtilityOperationResults(false, "<Error>Unknown Operation</Error>", DateTime.Now, DateTime.Now, 0);
                    break;
            }

            //get the date/times into the US format
            long StartTicks = Results.OperationStartTime.Ticks;
            Results.OperationStartTime = new DateTime(StartTicks, DateTimeKind.Unspecified);
            long EndTicks = Results.OperationEndTime.Ticks;
            Results.OperationEndTime = new DateTime(EndTicks, DateTimeKind.Unspecified);

            LogResults(Results);
            LogXMLResults(Action, Source, Target, Results);
            return Results;
        }

        static string ping_test(string ServerName)
        {
            //ping vars
            Ping pingSender = new Ping();
            int timeout = 5000;     //max of 5 seconds for ping 

            string remote_server = ServerName;
            string ping_time = "N/A";

            try
            {
                PingReply reply = pingSender.Send(remote_server, timeout);

                if (reply.Status == IPStatus.Success)
                {
                    //Console.WriteLine("Address: {0}", reply.Address.ToString());
                    //Console.WriteLine("RoundTrip time: {0}", reply.RoundtripTime);  //result in ms
                    //Console.WriteLine("Time to live: {0}", reply.Options.Ttl);
                    //Console.WriteLine("Don't fragment: {0}", reply.Options.DontFragment);
                    //Console.WriteLine("Buffer size: {0}", reply.Buffer.Length);
                    ping_time = reply.RoundtripTime.ToString();
                }
                else
                {
                    ping_time = reply.Status.ToString();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error with ping: " + e);
                ping_time = "Error: " + e.ToString();
            }
            return ping_time;
        }
        
        //use WMI to lookup IP routing metrics in case there are two adapters active (wired / wireless)
        static bool determine_ip_used()   
        {
            bool firstLoop = true;

            try
            {
                ManagementObjectSearcher searcher =
                    new ManagementObjectSearcher("root\\CIMV2",
                    "SELECT * FROM Win32_NetworkAdapterConfiguration");

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    if (queryObj["IPAddress"] != null)
                    {
                        String[] arrIPAddress = (String[])(queryObj["IPAddress"]);
                        foreach (String arrValue in arrIPAddress)
                        {
                            //Console.WriteLine("IPAddress: {0}", arrValue);
                            if ( (arrValue != "0.0.0.0") && (arrValue != null) )
                            {
                                if ( firstLoop  || ( (UInt32)queryObj["IPConnectionMetric"] < (UInt32)currentLowestMetric ) )
                                {
                                    currentIP = arrValue.ToString();
                                    currentEthernetDescription = queryObj["Description"].ToString();
                                    currentLowestMetric = (UInt32)queryObj["IPConnectionMetric"];
                                    firstLoop = false;

                                }
                            }
                        }
                    }
                }

                //Console.WriteLine("Description: {0}", currentEthernetDescription);
                //Console.WriteLine("IP Address: {0}", currentIP);
                //Console.WriteLine("IPConnectionMetric: {0}", currentLowestMetric.ToString());
                return true;
            }
            catch (ManagementException e)
            {
                Console.WriteLine("An error occurred while querying for WMI data: " + e.Message);
                return false;
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
                return false;
            }
        }

        static void LogTest(ActionType Action, string Source, string Target)
        {
            string strActivityEntry = String.Format("{0} \"{1}\" \"{2}\"", Action.ToString() , Source, Target);
            strarrActivityLog.Add(strActivityEntry);
            Output.WriteLine("Test:\n{0}", strActivityEntry);
        }

        static void LogResults(UtilityOperationResults Results)
        {
            IFormatProvider USCulture = new CultureInfo("en-US", false);    //convert the datetimes to US for printout
            string strActivityEntry = String.Format("\t{0}sec {1}B \"{2}\"\n", Results.OperationTime.TotalSeconds.ToString(USCulture), Results.TransferSize, Results.Message);
            strarrActivityLog.Add(strActivityEntry);
            Output.WriteLine("{0}", strActivityEntry);
        }
        
        static void LogXMLResults(ActionType Action, string Source, string Target, UtilityOperationResults Results)
        {
           
            strXMLResults += String.Format("<Test>{0}{1}</Test>", String.Format("<Operation Action='{0}' Source='{1}' Target='{2}' Success='{3}' Message='{4}'/>", Action, Source, Target, Results.Success, Results.Message), Results.ToString());
        }

        static void SaveResults(string ResultsListName)
        {
            try
            {
                #region List Update Procedure
                string MachineName = Environment.MachineName;
                string ListItemTitle = string.Format("{0} {1:dd/MM/yy hh:mm:ss}", MachineName, DateTime.Now.ToString(CultureInfo.InvariantCulture));
                string OutputFileName = string.Format("{0} {1:ddMMyy hhmmss}.xml", MachineName, DateTime.Now);
                string PostToListResponse = "";

                IFormatProvider USCulture = new CultureInfo("en-US", false);    //convert the datetimes to US for printout

                string strTestRunResults = "";
                strTestRunResults = "Copytimer Version: " + CopytimerVersion + System.Environment.NewLine + "Results List Name: " + ResultsListName + System.Environment.NewLine;

                foreach (string line in strarrActivityLog)
                {
                    strTestRunResults += line;
                }

                //find out each file's success and assign Success or just use the error message returned for the list
                //the actual Success message will still be visible in the XML files, this is to simply the list view
                if (FileDL1Success == true)
                    FileDL1Msg = "Success";
                if (FileUL1Success == true)
                    FileUL1Msg = "Success";
                if (FileDL2Success == true)
                    FileDL2Msg = "Success";
                if (FileUL2Success == true)
                    FileUL2Msg = "Success";
                if (FileDL3Success == true)
                    FileDL3Msg = "Success";
                if (FileUL3Success == true)
                    FileUL3Msg = "Success";
                if (warmupSuccess == true)
                    warmupMsg = "Success";

				//save working file
				FileStream ResultsFile = new FileStream(OutputFileName, FileMode.OpenOrCreate, FileAccess.Write);
				Byte[] ResultsFileBytes = System.Text.Encoding.UTF8.GetBytes(strXMLResults);
				ResultsFile.Write(ResultsFileBytes, 0, ResultsFileBytes.Length);
                ResultsFile.Close();

                //list update xml payload (must match list schema or it will fail)
                string strBatch = "<Method ID='1' Cmd='New'>" +
                    "<Field Name='ID'>New</Field>" +
                    "<Field Name='Title'>" + ListItemTitle + "</Field>" +
                    "<Field Name='Computer'>" + MachineName.ToString() + "</Field>" +
                    "<Field Name='DateAndTime'>" + DateTime.Now.ToString(CultureInfo.InvariantCulture) + "</Field>" +
                    "<Field Name='ServerName'>" + server_name.Host.ToString() + "</Field>" + 
                    "<Field Name='IP'>" + currentIP.ToString() + "</Field>" +
                    "<Field Name='EthernetCard'>" + currentEthernetDescription.ToString() + "</Field>" +
                    "<Field Name='WarmupTime'>" + warmupTime.ToString(USCulture)+ "</Field>" +
                    "<Field Name='WarmupMsg'>" + warmupMsg + "</Field>" +
                    "<Field Name='Ping'>" + ping_time.ToString() + "</Field>" +
                    "<Field Name='FileDLTime1'>" + dFileDLTime1.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileDL1Success'>" + FileDL1Msg + "</Field>" +
                    "<Field Name='FileULTime1'>" + dFileULTime1.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileUL1Success'>" + FileUL1Msg + "</Field>" +
                    "<Field Name='FileBytes1'>" + iFileSize1 + "</Field>" +
                    "<Field Name='FileDLTime2'>" + dFileDLTime2.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileDL2Success'>" + FileDL2Msg + "</Field>" +
                    "<Field Name='FileULTime2'>" + dFileULTime2.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileUL2Success'>" + FileUL2Msg + "</Field>" +
                    "<Field Name='FileBytes2'>" + iFileSize2 + "</Field>" +
                    "<Field Name='FileDLTime3'>" + dFileDLTime3.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileDL3Success'>" + FileDL3Msg + "</Field>" +
                    "<Field Name='FileULTime3'>" + dFileULTime3.ToString(USCulture) + "</Field>" +
                    "<Field Name='FileUL3Success'>" + FileUL3Msg + "</Field>" +
                    "<Field Name='FileBytes3'>" + iFileSize3 + "</Field>" +
                    "<Field Name='Details'>" + strTestRunResults + "</Field>" +
                "</Method>";

                //list batch update xml payload
                XmlDocument xmlDoc = new System.Xml.XmlDocument();
                System.Xml.XmlElement elBatch = xmlDoc.CreateElement("Batch");
                elBatch.SetAttribute("OnError", "Continue");
                elBatch.SetAttribute("ListVersion", "1");
                elBatch.InnerXml = strBatch;

                //list update routine
                ResultsList.Lists listService = new ResultsList.Lists();
                listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                XmlNode ndReturn = listService.UpdateListItems(ResultsListName, elBatch);

                //process return value
                string xpqSoapReturnRow = "//*[local-name() = 'Result' and namespace-uri() = 'http://schemas.microsoft.com/sharepoint/soap/']/*[local-name() = 'row' and namespace-uri() = '#RowsetSchema']";
                XmlNode returnRow = ndReturn.SelectSingleNode(xpqSoapReturnRow);
                if (returnRow != null)
                {
                    //get new list item ID
                    string strItemID = returnRow.Attributes["ows_ID"].Value;

                    //open working file to upload contents as attachment to recently created list item
                    ResultsFile = new FileStream(OutputFileName, FileMode.Open, FileAccess.Read);

                    int CloseXMLBytesLen = (int)(System.Text.Encoding.UTF8.GetBytes("</Results>").Length); //close xml just for server (doesnt include if upload of results works)

                    ResultsFileBytes = new Byte[ResultsFile.Length + CloseXMLBytesLen];
                    ResultsFile.Read(ResultsFileBytes, 0, (int)ResultsFile.Length);

                    Byte[] CloseXMLBytes = System.Text.Encoding.UTF8.GetBytes("</Results>"); //again format xml properly for server (its slightly diff than client version)
                    CloseXMLBytes.CopyTo(ResultsFileBytes, (int)ResultsFile.Length);

                    string ret = listService.AddAttachment(ResultsListName, strItemID, "Results.xml", ResultsFileBytes);
                    Output.WriteLine("Results File posted to: " + ret);
                    PostToListResponse = "Results File posted to: " + ret;
                    ResultsFile.Close();
                }
                else
                {
                    Output.WriteLine("Error:\n" + ndReturn.InnerXml);
                    PostToListResponse = "Error posting to list:\n" + ndReturn.InnerXml;
                }
                PostToListResponse = "<UploadResults>" + PostToListResponse + "</UploadResults></Results>";

                //add the information about whether the upload suceeded or not to the XML file
                ResultsFile = new FileStream(OutputFileName, FileMode.Append, FileAccess.Write);
                ResultsFileBytes = System.Text.Encoding.UTF8.GetBytes(PostToListResponse);
                ResultsFile.Write(ResultsFileBytes, 0, ResultsFileBytes.Length);
                ResultsFile.Close();

                #endregion
            }
            catch (WebException e)
            {
                Error.WriteLine(e);
            }
            catch (Exception e)
			{
				Error.WriteLine(e);
			}
        }

        static bool CreateCustomResultsList(string ListName, string Description, TextWriter Output, TextWriter Error)
        {
            /********************************************\
             * List Display Name                Type    *
             ********************************************
             * Announcements                    104     *
             * Contacts                         105     *
             * Custom List                      100     *   <--
             * Custom List in Datasheet View    120     *
             * DataSources                      110     *
             * Discussion Board                 108     *
             * Document Library                 101     *
             * Events                           106     *
             * Form Library                     115     *
             * Issues                           1100    *
             * Links                            103     *
             * Picture Library                  109     *
             * Survey                           102     *
             * Tasks                            107     *
            \********************************************/

            XmlDocument xmlDoc = new System.Xml.XmlDocument();
            XmlNode returnRow = null;
            string xpqSoapReturnRow = ".";
            try
            {            
                #region Create New List

                ResultsList.Lists listService = new ResultsList.Lists();
                listService.Credentials = System.Net.CredentialCache.DefaultCredentials;
                
                XmlNode ndList = listService.AddList(ListName, Description, 100); //100 is a custom List based on the above commented table
                returnRow = ndList.SelectSingleNode(xpqSoapReturnRow);
                
                #region Add Additional List Columns
                if (returnRow != null)
                {
                    //get new list item ID
                    string strListID = returnRow.Attributes["ID"].Value;
                    string strVersion = returnRow.Attributes["Version"].Value;

                    //NOTE: For some reason having spaces in Field Names gives an error.
                    //I have not been able to determine why this is. Perhaps they need to be %20 instead of a space?
                    //Either way this isn't required as it only makes it look a bit nicer
                    XmlNode ndNewFields = xmlDoc.CreateNode(XmlNodeType.Element, "Fields", "");
                    ndNewFields.InnerXml = "<Method ID='1'>" +
                       "<Field Type='Text' Name='Computer' DisplayName='Computer' Required='FALSE' FromBaseType='TRUE' Description='IP Address used by client for uploads / download'/>" +
                       "</Method><Method ID='2'>" +
                       "<Field Type='Text' Name='DateAndTime' DisplayName='DateAndTime' Required='FALSE' FromBaseType='TRUE' Description='Ping of the Server Name before test'/>" +
                       "</Method><Method ID='3'>" +
                       "<Field Type='Text' Name='ServerName' DisplayName='ServerName' Required='FALSE' FromBaseType='TRUE' Description='Ping of the Server Name before test'/>" +
                       "</Method><Method ID='4'>" +
                       "<Field Type='Text' Name='IP' DisplayName='IP' Required='FALSE' FromBaseType='TRUE' Description='IP Address used by client for uploads / download'/>" +
                       "</Method><Method ID='5'>" +
                       "<Field Type='Text' Name='EthernetCard' DisplayName='EthernetCard' Required='FALSE' FromBaseType='TRUE' Description='IP Address used by client for uploads / download'/>" +
                       "</Method><Method ID='6'>" +
                       "<Field Type='Text' Name='Ping' DisplayName='Ping' Required='FALSE' FromBaseType='TRUE' Description='Ping of the Server Name before test'/>" +
                       "</Method><Method ID='7'>" +
                       "<Field Type='Text' Name='WarmupTime' DisplayName='WarmupTime' Required='FALSE' FromBaseType='TRUE' Description='Warmup download before test in seconds'/>" +
                       "</Method><Method ID='8'>" +
                       "<Field Type='Text' Name='WarmupMsg' DisplayName='WarmupMsg' Required='FALSE' FromBaseType='TRUE' Description='Warmup Message response from the server'/>" +
                       "</Method><Method ID='9'>" + 
                       "<Field Type='Number' Name='FileDLTime1' DisplayName='FileDLTime1' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='10'>" +
                       "<Field Type='Text' Name='FileDL1Success' DisplayName='FileDL1Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1)'/>" +
                       "</Method><Method ID='11'>" +
                       "<Field Type='Number' Name='FileULTime1' DisplayName='FileULTime1' Required='FALSE' FromBaseType='TRUE' Description='Upload time for File 1'/>" +
                       "</Method><Method ID='12'>" +
                       "<Field Type='Text' Name='FileUL1Success' DisplayName='FileUL1Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='13'>" +
                       "<Field Type='Number' Name='FileBytes1' DisplayName='FileBytes1' Required='FALSE' FromBaseType='TRUE' Description='File size of File 1 (Bytes)'/>" +
                       "</Method><Method ID='14'>" +
                       "<Field Type='Number' Name='FileDLTime2' DisplayName='FileDLTime2' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 2'/>" +
                       "</Method><Method ID='15'>" +
                       "<Field Type='Text' Name='FileDL2Success' DisplayName='FileDL2Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='16'>" +
                       "<Field Type='Number' Name='FileULTime2' DisplayName='FileULTime2' Required='FALSE' FromBaseType='TRUE' Description='Upload time for File 2 (ms)'/>" +
                       "</Method><Method ID='17'>" +
                       "<Field Type='Text' Name='FileUL2Success' DisplayName='FileUL2Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='18'>" +
                       "<Field Type='Number' Name='FileBytes2' DisplayName='FileBytes2' Required='FALSE' FromBaseType='TRUE' Description='File size of File 2 (Bytes)'/>" +
                       "</Method><Method ID='19'>" +
                       "<Field Type='Number' Name='FileDLTime3' DisplayName='FileDLTime3' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 3'/>" +
                       "</Method><Method ID='20'>" +
                       "<Field Type='Text' Name='FileDL3Success' DisplayName='FileDL3Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='21'>" +
                       "<Field Type='Number' Name='FileULTime3' DisplayName='FileULTime3' Required='FALSE' FromBaseType='TRUE' Description='Upload time for File 3'/>" +
                       "</Method><Method ID='22'>" +
                       "<Field Type='Text' Name='FileUL3Success' DisplayName='FileUL3Success' Required='FALSE' FromBaseType='TRUE' Description='Download time for File 1'/>" +
                       "</Method><Method ID='23'>" +
                       "<Field Type='Number' Name='FileBytes3' DisplayName='FileBytes3' Required='FALSE' FromBaseType='TRUE' Description='File size of File 3 (Bytes)'/>" +
                       "</Method><Method ID='24'>" +
                       "<Field Type='Note' Name='Details' DisplayName='Details' Required='FALSE' FromBaseType='TRUE' Description='Details of the test steps'/>" +
                       "</Method>";
                    XmlNode ndReturn = listService.UpdateList(strListID, null, ndNewFields, null, null, strVersion);
                }
                #endregion
            #endregion

                #region Update Default View

                ResultsView.Views viewService = new ResultsView.Views();
                viewService.Credentials = System.Net.CredentialCache.DefaultCredentials;

                XmlNode ndView = viewService.GetView(ListName, "");
                returnRow = ndView.SelectSingleNode(xpqSoapReturnRow);

                if (returnRow != null)
                {
                    string strViewName = returnRow.Attributes["Name"].Value;
                    string strViewFields = "<FieldRef Name='Computer' />" +
                        "<FieldRef Name='DateAndTime' />" +
                        "<FieldRef Name='ServerName' />" +
                        "<FieldRef Name='IP' />" +
                        "<FieldRef Name='EthernetCard' />" +
                        "<FieldRef Name='Ping' />" +
                        "<FieldRef Name='WarmupTime' />" +
                        "<FieldRef Name='WarmupMsg' />" +
                        "<FieldRef Name='FileDLTime1' />" +
                        "<FieldRef Name='FileDL1Success' />" +
                        "<FieldRef Name='FileULTime1' />" +
                        "<FieldRef Name='FileUL1Success' />" +
                        "<FieldRef Name='FileBytes1' />" +
                        "<FieldRef Name='FileDLTime2' />" +
                        "<FieldRef Name='FileDL2Success' />" +
                        "<FieldRef Name='FileULTime2' />" +
                        "<FieldRef Name='FileUL2Success' />" +
                        "<FieldRef Name='FileBytes2' />" +
                        "<FieldRef Name='FileDLTime3' />" +
                        "<FieldRef Name='FileDL3Success' />" +
                        "<FieldRef Name='FileULTime3' />" +
                        "<FieldRef Name='FileUL3Success' />" +
                        "<FieldRef Name='FileBytes3' />";
                    XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
                    ndViewFields.InnerXml = strViewFields;

                    XmlNode ndReturn = viewService.UpdateView(ListName, strViewName, null, null, ndViewFields, null, null, null);
                }
                #endregion
            }
            catch (Exception ex)
            {
                Error.WriteLine("Error:\n" + ex.Message + "\nStackTrace:\n" + ex.StackTrace);
                return false;
            }
            return true;
        }
    }
 }

